use crate::argument::{Argument, RunArgument};
use crate::constant::c::{CONFIG_FILE_NAME, UPDATE_SETTING_FILE_NAME};
use crate::util::Util;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tracing::{debug, info};

pub mod channel_config;
pub mod device_config;
pub mod native_version_config;
pub mod update_config;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    port: u16,
    update_setting_path: PathBuf,
    device_list_path: PathBuf,
}

impl Config {
    pub fn new(port: u16, update_setting_path: PathBuf, device_list_path: PathBuf) -> Self {
        Self {
            port,
            update_setting_path,
            device_list_path,
        }
    }

    pub fn with_argument(argument: &RunArgument) -> Self {
        let config_path = argument
            .config_path()
            .cloned()
            .unwrap_or_else(|| Util::app_dirs().config_dir().join(CONFIG_FILE_NAME));

        debug!("optional config source: {:?}", config_path);

        let update_setting_path = Util::app_dirs().config_dir().join(UPDATE_SETTING_FILE_NAME);

        let c = config::Config::builder()
            .set_default("port", 11850)
            .unwrap()
            .set_default("update_setting_path", update_setting_path.to_str())
            .unwrap()
            .add_source(config::File::with_name(config_path.to_str().unwrap()).required(false))
            .set_override_option("port", argument.port().clone())
            .unwrap()
            .build()
            .unwrap()
            .try_deserialize()
            .unwrap();

        c
    }

    pub fn port(&self) -> u16 {
        self.port
    }

    pub fn update_setting_path(&self) -> &PathBuf {
        &self.update_setting_path
    }

    pub fn device_list_path(&self) -> &PathBuf {
        &self.device_list_path
    }
}
